package com.edu.buservice.biz.impl;

import cn.dev33.satoken.stp.StpUtil;
import cn.hutool.core.collection.CollectionUtil;
import cn.hutool.crypto.SecureUtil;
import com.baomidou.mybatisplus.core.toolkit.StringUtils;
import com.edu.buservice.biz.PermissionManger;
import com.edu.buservice.biz.RoleManger;
import com.edu.buservice.biz.TenantManger;
import com.edu.buservice.biz.UserManger;
import com.edu.buservice.biz.config.CommonConfig;
import com.edu.buservice.biz.covert.TenantCovert;
import com.edu.buservice.biz.covert.UserInfoCovert;
import com.edu.buservice.biz.enums.DomainEnum;
import com.edu.buservice.biz.model.Request.QueryUserRequest;
import com.edu.buservice.biz.model.Request.UpdateUserRequest;
import com.edu.buservice.biz.model.Request.UserRequest;
import com.edu.buservice.biz.model.Response.LabelTenantResponse;
import com.edu.buservice.biz.model.dto.TenantInfoDTO;
import com.edu.buservice.biz.model.dto.UpdateUserInfoDTO;
import com.edu.buservice.dal.model.SysPermissions;
import com.edu.buservice.dal.model.SysRoles;
import com.edu.buservice.dal.model.SysUsers;
import com.edu.buservice.dal.service.SysUsersService;
import com.edu.buservice.facade.constants.SessionKeyConstant;
import com.edu.buservice.facade.model.response.BaseUserInfoDTO;
import com.edu.buservice.util.model.R;
import com.edu.buservice.util.model.TenantUtil;
import com.edu.buservice.util.model.UserInfoDTO;
import com.edu.buservice.util.model.enums.ErrorCodeEnum;
import com.edu.buservice.util.model.error.BizException;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @program: KQAIA
 * @description:
 * @author: 无恙
 * @create: 2025-02-09 18:39
 **/
@Service
@Slf4j
public class UserMangerImpl implements UserManger {

	@Autowired
	private SysUsersService sysUsersService;

	@Autowired
	private RoleManger roleManger;

	@Autowired
	private PermissionManger permissionManger;

	@Autowired
	private TenantManger tenantManger;

	@Autowired
	private CommonConfig commonConfig;

	@Override
	public List<SysUsers> getUserInfoByPhone(String phone) {

		if (StringUtils.isBlank(phone)) {
			throw new BizException(ErrorCodeEnum.PARAM_MISSING);
		}

		List<SysUsers> userInfoByPhone = sysUsersService.getUserInfoByPhone(phone);

		if (Objects.isNull(userInfoByPhone)) {
			throw new BizException(ErrorCodeEnum.USER_NOT_FOUND);
		}

		return userInfoByPhone;
	}

	@Override
	public List<SysUsers> getUserInfoWithoutTenant(String userId, String phone) {
		return sysUsersService.getUserInfoByUserIdOrPhone(userId, phone);
	}

	/**
	 * 根据用户ID获取用户信息
	 *
	 * 此方法首先检查传入的用户ID是否为空或无效，如果是，则抛出业务异常，提示参数缺失
	 * 接着，通过用户ID获取用户的基本信息、角色信息和权限信息
	 * 最后，将这些信息转换为UserInfoDTO对象并返回
	 *
	 * @param userId 用户ID，用于查询用户信息，不能为空或空字符串
	 * @return UserInfoDTO 包含用户基本信息、角色和权限的DTO对象
	 * @throws BizException 如果用户ID为空或无效，抛出业务异常
	 */
	@Override
	public UserInfoDTO getUserInfoById(String userId) {

	    // 检查用户ID是否为空或无效，如果为空或无效，则抛出业务异常
	    if (StringUtils.isBlank(userId)) {
	        throw new BizException(ErrorCodeEnum.PARAM_MISSING);
	    }

	    // 通过用户ID获取用户的基本信息
	    SysUsers sysUsers = sysUsersService.getUserInfoById(userId);

	    // 通过用户ID获取用户的角色信息
	    SysRoles rolesByUserId = roleManger.getRolesByUserId(userId);

	    // 通过角色ID获取用户的权限信息
	    List<SysPermissions> permissionsByRoleId = permissionManger.getPermissionsByRoleId(rolesByUserId.getId());

	    // 将用户的基本信息、角色信息和权限信息转换为UserInfoDTO对象并返回
	    return UserInfoCovert.convertUserInfoDTO(sysUsers, rolesByUserId, permissionsByRoleId);
	}

	/**
	 * 添加用户方法
	 *
	 * 根据用户请求信息添加新用户，并为其分配默认角色
	 * 该方法使用事务管理，确保数据一致性
	 *
	 * @param userRequest 用户请求对象，包含用户相关信息
	 * @return 返回表示操作结果的字符串
	 * @throws BizException 如果参数缺失或错误，则抛出业务异常
	 */
	@Override
	@Transactional(rollbackFor = Exception.class)
	public R<String> addUser(UserRequest userRequest) {
		log.info("开始添加用户：{}", userRequest);

	    // 检查用户请求是否为空
	    if(Objects.isNull(userRequest)){
	        throw new BizException(ErrorCodeEnum.PARAM_MISSING);
	    }

	    // 获取用户请求中的域
	    String domain = userRequest.getDomain();

	    // 根据域获取对应的枚举类型
	    DomainEnum byDomain = DomainEnum.getByDomain(domain);

	    // 检查域参数是否有效
	    if(Objects.isNull(byDomain)){
	        throw new BizException(ErrorCodeEnum.PARAM_ERROR, "域参数错误或者不可以为null");
	    }

	    // 根据不同的域类型，获取对应的默认角色ID和租户ID
	    String roleId;
	    if(DomainEnum.USER.equals(byDomain)){
	        roleId = commonConfig.getUserDefaultRole();
			userRequest.setTenantId(commonConfig.getUserTenantId());
	        // 初始化用户侧角色
	        TenantUtil.setCurrentTenantId(commonConfig.getUserTenantId());
	    }else if(DomainEnum.ADMIN.equals(byDomain)) {
	        roleId = commonConfig.getAdminDefaultRole();
			userRequest.setTenantId(commonConfig.getAdminTenantId());
	        // 初始化管理员侧角色
	        TenantUtil.setCurrentTenantId(commonConfig.getAdminTenantId());
	    }else {
	        roleId = commonConfig.getMerchantDefaultRole();
	        // 初始化商户侧角色，并检查租户ID是否为空
	        String tenantId = userRequest.getTenantId();
	        if(StringUtils.isBlank(tenantId)){
	            throw new BizException(ErrorCodeEnum.PARAM_ERROR, "租户ID不可以为null");
	        }
			//校验租户ID
			TenantInfoDTO tenantInfoByTenantId = tenantManger.getTenantInfoByTenantId(tenantId);

			if(Objects.isNull(tenantInfoByTenantId)){
				throw new BizException(ErrorCodeEnum.TENANT_NOT_EXIST);
			}

	        // 初始化租户ID
	        TenantUtil.setCurrentTenantId(tenantId);
	    }

	    // 对用户密码进行MD5加密
	    String decryptPassword = SecureUtil.md5(userRequest.getPassword());

	    // 将加密后的密码设置回用户请求对象
	    userRequest.setPassword(decryptPassword);

	    // 将用户请求对象转换为用户信息对象
	    SysUsers sysUsers = UserInfoCovert.CovertByUserRequest(userRequest);

	    // 调用服务层方法添加用户信息，并获取用户ID
	    String userId = sysUsersService.addUserInfo(sysUsers);

	    // 添加用户角色关系
	    roleManger.addUserRole(userId, roleId);

	    // 返回成功结果和用户ID
	    return R.success(userId);
	}

	@Override
	public R<List<LabelTenantResponse>> queryByTenantLabel(String phone) {

		if(StringUtils.isBlank(phone)) {
			throw new BizException(ErrorCodeEnum.PARAM_MISSING);
		}

		List<SysUsers> userInfoByPhone = this.getUserInfoByPhone(phone);

		if(CollectionUtil.isEmpty(userInfoByPhone)){
			throw new BizException(ErrorCodeEnum.USER_NOT_FOUND);
		}

		//获取租户Id
		Set<String> tenantIds = userInfoByPhone.stream().map(SysUsers::getTenantId).collect(Collectors.toSet());

		//去查询租户信息
		List<TenantInfoDTO> tenantInfoByTenantIds = tenantManger.batchQueryTenantInfo(new ArrayList<>(tenantIds));

		if(CollectionUtil.isEmpty(tenantInfoByTenantIds)){
			throw new BizException(ErrorCodeEnum.TENANT_NOT_FOUND);
		}

		return R.success(tenantInfoByTenantIds.stream().map(TenantCovert::convert).toList());

	}

	@Override
	public List<BaseUserInfoDTO> queryUserByIds(List<String> userIds) {

		if(CollectionUtil.isEmpty(userIds)) {
			throw new BizException(ErrorCodeEnum.PARAM_MISSING);
		}


		List<SysUsers> userInfoByIds = sysUsersService.getUserInfoByIds(userIds);

		if(CollectionUtil.isEmpty(userInfoByIds)) {
			throw new BizException(ErrorCodeEnum.USER_NOT_FOUND);
		}

		return userInfoByIds.stream().map(UserInfoCovert::covertToUserInfo).toList();

	}

	@Override
	public R<List<BaseUserInfoDTO>> queryUserByCondition(QueryUserRequest userRequest) {

		if(Objects.isNull(userRequest)) {
			throw new BizException(ErrorCodeEnum.PARAM_MISSING);
		}

		SysUsers sysUsers = UserInfoCovert.convertToSysUsers(userRequest);

		List<SysUsers> userInfoByCondition = sysUsersService.getUserInfoByCondition(sysUsers);

		if(CollectionUtil.isEmpty(userInfoByCondition)) {
			return R.success(new ArrayList<>());
		}

		//去重复根据手机号
		userInfoByCondition = userInfoByCondition.stream()
				.collect(Collectors.collectingAndThen(Collectors.toCollection(() -> new TreeSet<>(Comparator.comparing(SysUsers::getPhone))), ArrayList::new));

		return R.success(userInfoByCondition.stream().map(UserInfoCovert::covertToUserInfo).toList());


	}

	@Override
	public R<Boolean> updateUser(UpdateUserInfoDTO updateUserInfoDTO) {

		if(Objects.isNull(updateUserInfoDTO)) {
			throw new BizException(ErrorCodeEnum.PARAM_MISSING);
		}

		if(StringUtils.isBlank(updateUserInfoDTO.getUserId())) {
			throw new BizException(ErrorCodeEnum.PARAM_MISSING);
		}

		SysUsers sysUsers = UserInfoCovert.convertToSysUsers(updateUserInfoDTO);

		if (sysUsersService.updateUserInfo(sysUsers)) {

			return R.success(true);
		}

		throw new BizException(ErrorCodeEnum.DATABASE_ERROR, "更新用户信息失败");

	}

	@Override
	public R<Boolean> updateUserInfo(UpdateUserRequest updateUserRequest) {

		if(Objects.isNull(updateUserRequest)) {
			throw new BizException(ErrorCodeEnum.PARAM_MISSING);
		}

		//获取用户ID
		String userId = StpUtil.getLoginIdAsString();

		if(StringUtils.isBlank(userId)) {
			throw new BizException(ErrorCodeEnum.USER_NOT_ACTIVATED);
		}

		UpdateUserInfoDTO userInfoDTO = new UpdateUserInfoDTO();

		userInfoDTO.setUserId(userId);
		userInfoDTO.setPhone(updateUserRequest.getPhone());
		userInfoDTO.setEmail(updateUserRequest.getEmail());
		userInfoDTO.setAvatarUrl(updateUserRequest.getAvatarUrl());
		userInfoDTO.setUsername(updateUserRequest.getUserName());

		R<Boolean> booleanR = this.updateUser(userInfoDTO);

		if(!booleanR.isSuccess()) {
			throw new BizException(ErrorCodeEnum.DATABASE_ERROR, "更新用户信息失败");
		}

		UserInfoDTO userInfo = StpUtil.getSession().get(SessionKeyConstant.USER_INFO, new UserInfoDTO());

		Optional.ofNullable(userInfoDTO.getPhone()).ifPresent(userInfo::setPhone);
		Optional.ofNullable(userInfoDTO.getEmail()).ifPresent(userInfo::setEmail);
		Optional.ofNullable(userInfoDTO.getAvatarUrl()).ifPresent(userInfo::setAvatarUrl);
		Optional.ofNullable(userInfoDTO.getStatus()).ifPresent(userInfo::setStatus);
		Optional.ofNullable(userInfoDTO.getUsername()).ifPresent(userInfo::setUsername);

		StpUtil.getSession().set(SessionKeyConstant.USER_INFO, userInfo);

		return R.success(true);

	}
}
